package com.clx.channelHandler.hander;

import com.clx.compress.CompressWrapper;
import com.clx.compress.Compressor;
import com.clx.compress.CompressorFactory;
import com.clx.enumeration.RequestType;
import com.clx.serialize.Serializer;
import com.clx.serialize.SerializerFactory;
import com.clx.transport.message.CrpcRequest;
import com.clx.transport.message.MessageFormatConstant;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

/**
 * 4B magic（魔术值） ---》crpc.getBytes()
 * 1B version(版本) ---> 1
 * 2B header length 首部的长度
 * 4B full length 报文总长度
 * 1B serialize
 * 1B compress
 * 1B requestType
 * 8B requestId
 *
 * body
 * */
/**
 * 出站时，第一个经过的处理器
 * */
@Slf4j
public class CrpcRequestEncoder extends MessageToByteEncoder<CrpcRequest> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, CrpcRequest crpcRequest, ByteBuf byteBuf) throws Exception {
        // 4个字节的魔术值
        byteBuf.writeBytes(MessageFormatConstant.MAGIC);
        // 1个字节的版本号
        byteBuf.writeByte(MessageFormatConstant.VERSION);
        // 2个字节的头部的长度
        byteBuf.writeShort(MessageFormatConstant.HEADER_LENGTH);
        //  总长度不清楚，不知道body的长度 writeIndex（写指针）
        byteBuf.writerIndex(byteBuf.writerIndex() + MessageFormatConstant.FULL_FIELD_LENGTH);
        // 3个类型
        byteBuf.writeByte(crpcRequest.getRequestType());
        byteBuf.writeByte(crpcRequest.getSerializeType());
        byteBuf.writeByte(crpcRequest.getCompressType());
        // 8字节的请求id
        byteBuf.writeLong(crpcRequest.getRequestId());
        byteBuf.writeLong(crpcRequest.getTimeStamp());

        // 如果是心跳请求，就不处理请求体
        if (crpcRequest.getRequestType() == RequestType.HEART_BEAT.getId()) {
            // 处理一下总长度，其实总长度 = header长度
            int writerIndex = byteBuf.writerIndex();
            byteBuf.writerIndex(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGHT + MessageFormatConstant.HEADER_FIELD_LENGTH);
            byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH);
            // 将写指针归位
            byteBuf.writerIndex(writerIndex);
            return;
        }

        // 写入请求体（requestPayload）
        // 1.根据配置的序列化方式进行序列化
        // 怎么实现序列化 1,工具类 耦合性很高 如果以后我想替换序列化方式，很难
        byte[] body = null;
        if (crpcRequest.getRequestPayload() != null){
        Serializer serializer = SerializerFactory.getSerialze(crpcRequest.getSerializeType()).getSerializer();
        body = serializer.serialize(crpcRequest.getRequestPayload());
        // 2.根据配置的压缩方式进行压缩
            Compressor compressor = CompressorFactory.getCompressor(crpcRequest.getCompressType()).getCompressor();
            body = compressor.compress(body);
        }

        if (body != null) {
            byteBuf.writeBytes(body);
        }
        // 重新处理报文的总长度
        // 先保存当前写指针的位置
        int writerIndex = byteBuf.writerIndex();
        // 将写指针的位置移动到总长度的位置上
        byteBuf.writerIndex(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGHT + MessageFormatConstant.HEADER_FIELD_LENGTH);
        byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH + body.length);

        // 将写指针归位
        byteBuf.writerIndex(writerIndex);
        if (log.isDebugEnabled()) {
            log.debug("请求【{}】以及完成报文的编码。", crpcRequest.getRequestId());
        }
    }

}